﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.IO;

namespace WindowsFormsApplication1
{
    class EcgSD
    {
        private FormPrincipal form;
        private Boolean mostrarAceleracao;
        private int escalaTempoPictureBox;
        private double ganhoSD;
        private int deslocamentoSD;
        private int posicaoArquivo;
        private PictureBox[] pictureBoxSD = new PictureBox[4];
        private int[,] amostrasSD = new int[3, 69120];
        private int[,] amostrasAceleracao = new int[3, 69120];
        private OpenFileDialog dlg;
        private FileStream inputStream;
        private BinaryReader br;
        private int numeroTotalSetores;
        private MeuRecordTypeSD dadosSetorECG;
        private int tempoTotalMinutos;
        private int tempoTotalSegundos;
        private int avancaRecua;
        private int pctboxSelectedSD;
        private int derivacaoSelecionada;
        private int posicaoSelecionada;
        private int[] amostrasDetalhada = new int[9 * 960 + 1]; //Armazena no máximo 3s de dados
        private int tamanhoDetalhe = 9 * 960;
        private int posicaoAmostra;
		private Analisador analisador;

        public int getAmostrasSD(int i,int j)
        {
            return amostrasSD[i,j];
        }

        public int[] getAmostrasDetalhada()
        {
            return amostrasDetalhada;
        }

        public void setAvancaRecua(int avancaRecua)
        {
            this.avancaRecua = avancaRecua;
        }

        public int getAvancaRecua()
        {
            return avancaRecua;
        }

        public void setForm(FormPrincipal form)
        {
            this.form = form;
        }

        public void inicializarTab()
        {
            //Zera textbox de tempo
            form.msktxtbxInicio.Text = "000000";
            form.msktxtbxFim.Text = "000000";
            form.msktxtbxAtual.Text = "000000";

            //Indexa os pictures boxes a serem usados
            pictureBoxSD[0] = form.pctbxSD1;
            pictureBoxSD[1] = form.pctbxSD2;
            pictureBoxSD[2] = form.pctbxSD3;
            pictureBoxSD[3] = form.pctbxSD4;

            //Parametros de para plotagem
            ganhoSD = 1;
            deslocamentoSD = 0;
            mostrarAceleracao = false;

            //EscalaHorPic eh o numero total de amostras em um Picture
            escalaTempoPictureBox = 7680; //8*960 = 7680

            //Desativa botão fazer medidas
            form.btnFazerMedidas.Enabled = false;
        }

        public void plotaGrade()
        {
            //RGB(250, 200, 100) eh a cor mais parecida com aqueles papeis milimetrados
            Color corLinha = Color.FromArgb(255, 250, 200, 100);
            for (int i = 0; i < 4; i++)
            {
                pictureBoxSD[i].Image = desenhaGrade(pictureBoxSD[i].Width, pictureBoxSD[i].Height, corLinha);
            }
        }

        private Bitmap desenhaGrade(int comprimento, int altura, Color cor)
        {
            int passoAltura = altura / 30;
            int passoComprimento = 960;

            // Estou Criando um Objeto do tipo BITMAP - Uma Imagem
            Bitmap objBMP;

            // Criando Objeto do Tipo Imagem
            Graphics objGrafico;

            // Determinando qual sera a altura/largura da imagem BMP; estou criando uma area que ocupa a tela inteira
            objBMP = new Bitmap(comprimento, altura);

            // Adicionando a Imagem BMP ao objeto grafico, que sera usado para mostrar a imagem
            objGrafico = Graphics.FromImage(objBMP);

            // Determinando a cor de fundo da imagem
            //Color representa ARGB (Alpha, Red, Green, Blue) o melhor e deixar como White
            objGrafico.Clear(Color.White);

            // Criando objeto usado para desenhar linhas e curvas
            Pen p = new Pen(cor, 0);

            //desenha as linhas da grade
            for (int i = 1; i <= altura / passoAltura; i++)
            {
                objGrafico.DrawLine(p, 0, i * passoAltura, comprimento, i * passoAltura);
            }

            //desenha as colunas
            for (int i = 1; i * passoComprimento <= escalaTempoPictureBox; i++)
            {
                objGrafico.DrawLine(p, i * passoComprimento * comprimento / escalaTempoPictureBox, 0, i * passoComprimento * comprimento / escalaTempoPictureBox, altura);
            }

            return objBMP;
        }

        public void carregaArquivo()
        {

            //Seleciona arquivo
            if (dlg == null)
                dlg = new OpenFileDialog();
            dlg.Title = "Selecione o arquivo com os dados do ECG para analisar";
            dlg.Filter = "ecg arquivos (*.ttt)|*.ttt|Todos os arquivos (*.*)|*.*";
            dlg.ShowDialog();

            //Verifica se algum arquivo foi selecionado
            if (dlg.FileName != "")
            {
                posicaoArquivo = 0;
                //Abre arquivo selecionado
                inputStream = new FileStream(dlg.FileName, FileMode.Open, FileAccess.Read);
                //streamReader = new StreamReader(inputStream);
                br = new BinaryReader(inputStream);

                //Calcula o número total de setores a serem lidos
                numeroTotalSetores = (int)inputStream.Length / 512 + 1;

                //A cada 12 (960/(20*4)) setores = 1 minuto
                tempoTotalSegundos = (numeroTotalSetores / 12);
                tempoTotalMinutos = (numeroTotalSetores / 12) / 60;
				atualizaTelaDadosSD();

                //Atualiza tempo total do arquivo lido
                form.msktxtbxFim.Text = String.Format("{0:D2}{1:D2}{2:D2}", tempoTotalMinutos / 60, tempoTotalMinutos % 60, tempoTotalSegundos % 60);

                //Na carga, a posição inicial é em zero
                form.msktxtbxAtual.Text = "000000";

                form.btnReset.Enabled = true;
                form.btnAvancar.Enabled = true;
                form.btnRecuar.Enabled = true;
            }
            dlg.Dispose();
        }

        private void atualizaTelaDadosSD()
        {
          //  separaDados();
          //  rePlota();
		//	realizaAnaliseMitDTW();
			
			TreinamentoHiperCubo.treinaV1();
			TreinamentoHiperCubo.treinaV2();
			TreinamentoHiperCubo.treinaV4();
			TreinamentoHiperCubo.treinaV5();
			 
			realizaAnaliseMitHiperCubo();
        }

        private void separaDados()
        {
            dadosSetorECG = new MeuRecordTypeSD();
            int[] expansao2 = new int[12];
            int nib1, nib2, nib3, canal1, canal2, canal3;
            int tX, tY, tZ, Ctl; //temporarios dos dados acelerometro
            tX = tY = tZ = Ctl = 0;
            posicaoAmostra = 0;

            //de cada canal, 80 inteiros serão escritos por setor
            for (posicaoAmostra = 0; posicaoAmostra <= 4 * escalaTempoPictureBox + 4 * 960; )
            {
                if (inputStream.Position < inputStream.Length)
                {
                    //Le setor e o organiza
                    dadosSetorECG.setIdentificacao(br.ReadInt16());
                    dadosSetorECG.setExpansao1(br.ReadByte());
                    dadosSetorECG.setTipoCabo(br.ReadByte());
                    dadosSetorECG.setNumSetor(br.ReadInt32());
                    for (int i = 0; i < 12; i++)
                    {
                        expansao2[i] = br.ReadInt16();
                    }
                    dadosSetorECG.setExpansao2(expansao2);
                    dadosSetorECG.setDadosECG(br.ReadBytes(480));
                }
                else
                {
                    //Le setor e o organiza
                    byte[] zeros = new byte[480];
                    dadosSetorECG.setIdentificacao(0);
                    dadosSetorECG.setExpansao1(0);
                    dadosSetorECG.setTipoCabo(0);
                    dadosSetorECG.setNumSetor(0);
                    for (int i = 0; i < 12; i++)
                    {
                        expansao2[i] = 0;
                    }
                    dadosSetorECG.setExpansao2(expansao2);
                    dadosSetorECG.setDadosECG(zeros);
                }

                //Trata os dados
                for (int kk = 0; kk < dadosSetorECG.getDadosECG().Length; kk = kk + 24)
                {
                    for (int bloco = 0; bloco < 4; bloco++)
                    {

                        nib1 = dadosSetorECG.getDadosECG()[kk + 1 + bloco * 6] / 16;
                        dadosSetorECG.getDadosECG()[kk + 1 + bloco * 6] = (byte)(dadosSetorECG.getDadosECG()[kk + 1 + bloco * 6] % 16);
                        nib2 = dadosSetorECG.getDadosECG()[kk + 3 + bloco * 6] / 16;
                        dadosSetorECG.getDadosECG()[kk + 3 + bloco * 6] = (byte)(dadosSetorECG.getDadosECG()[kk + 3 + bloco * 6] % 16);
                        nib3 = dadosSetorECG.getDadosECG()[kk + 5] / 16;
                        dadosSetorECG.getDadosECG()[kk + 5 + bloco * 6] = (byte)(dadosSetorECG.getDadosECG()[kk + 5 + bloco * 6] % 16);

                        if (bloco == 0)
                            tX = nib3 * 256 + nib2 * 16 + nib1;
                        else if (bloco == 1)
                            tY = nib3 * 256 + nib2 * 16 + nib1;
                        else if (bloco == 2)
                            tZ = nib3 * 256 + nib2 * 16 + nib1;
                        else if (bloco == 3)
                            Ctl = nib3 * 256 + nib2 * 16 + nib1;


                        //Calcula as amplitudes de cada canal - 12 bits
                        canal1 = dadosSetorECG.getDadosECG()[kk + bloco * 6] + dadosSetorECG.getDadosECG()[kk + 1 + bloco * 6] * 256;
                        canal2 = dadosSetorECG.getDadosECG()[kk + 2 + bloco * 6] + dadosSetorECG.getDadosECG()[kk + 3 + bloco * 6] * 256;
                        canal3 = dadosSetorECG.getDadosECG()[kk + 4 + bloco * 6] + dadosSetorECG.getDadosECG()[kk + 5 + bloco * 6] * 256;

                        //Registra as amplitudes de cada canal
                        amostrasSD[0, posicaoAmostra] = canal1;
                        amostrasSD[1, posicaoAmostra] = canal2;
                        amostrasSD[2, posicaoAmostra] = canal3;

                        //Registra os valores das aceleracões
                        amostrasAceleracao[0, posicaoAmostra] = tX;
                        amostrasAceleracao[1, posicaoAmostra] = tY;
                        amostrasAceleracao[2, posicaoAmostra] = tZ;

                        posicaoAmostra++;
                    }
                }
            }
        }

        public void rePlota() //plota tudo novamente com grade etc...
        {
            int p1, p2, p3;
            double[] novox = new double[3];
            double[] antigox = new double[3];
            double[] novoy = new double[3];
            double[] antigoy = new double[3];
            Graphics objGrafico;

            //Plota a grade novamente
            plotaGrade();

            Pen p = new Pen(Color.Black, 0);

            for (int pictureBoxSelecionado = 0; pictureBoxSelecionado < 4; pictureBoxSelecionado++)
            {
                //faz para os 4 pics
                objGrafico = Graphics.FromImage(pictureBoxSD[pictureBoxSelecionado].Image);

                //modificando o passo teremos um maior ou menor grau de detalhe
                for (int posicaoX = 0; posicaoX < escalaTempoPictureBox; posicaoX++)
                {
                    //Imprime aceleração
                    if (mostrarAceleracao)
                    {
                        p1 = amostrasAceleracao[0, posicaoX + escalaTempoPictureBox * pictureBoxSelecionado];
                        p2 = amostrasAceleracao[0, posicaoX + escalaTempoPictureBox * pictureBoxSelecionado];
                        p3 = amostrasAceleracao[0, posicaoX + escalaTempoPictureBox * pictureBoxSelecionado];
                    }
                    else //Imprime batimentos
                    {
                        p1 = amostrasSD[0, posicaoX + escalaTempoPictureBox * pictureBoxSelecionado] + deslocamentoSD;
                        p2 = amostrasSD[1, posicaoX + escalaTempoPictureBox * pictureBoxSelecionado] + deslocamentoSD;
                        p3 = amostrasSD[2, posicaoX + escalaTempoPictureBox * pictureBoxSelecionado] + deslocamentoSD;
                    }

                    p1 = (int)((p1) * ganhoSD);
                    p2 = (int)((p2) * ganhoSD);
                    p3 = (int)((p3) * ganhoSD);

                    novoy[0] = (1 - (double)p1 / form.getMAX()) * pictureBoxSD[pictureBoxSelecionado].Height / 3;             //t1, ou Filtro60M8 ou Filtro60M16
                    novoy[1] = (2 - (double)p2 / form.getMAX()) * pictureBoxSD[pictureBoxSelecionado].Height / 3;
                    novoy[2] = (3 - (double)p3 / form.getMAX()) * pictureBoxSD[pictureBoxSelecionado].Height / 3;


                    for (int canal = 0; canal < 3; canal++) //são 3 canais mostrados
                    {
                        //passo do eixo X (pictureBoxSD[pictureBoxSelecionado].Width / escalaTempoPictureBox)
                        novox[canal] = posicaoX * pictureBoxSD[pictureBoxSelecionado].Width / escalaTempoPictureBox;  //calcula novo x
                        if (novox[canal] == 0) //vê se é zero >> está começando agora, i e, o anterior é igual
                        {
                            antigox[canal] = 0;
                            antigoy[canal] = novoy[canal];
                        }
                        //Desenha
                        objGrafico.DrawLine(p, (int)antigox[canal], (int)antigoy[canal], (int)novox[canal], (int)novoy[canal]);
						
                        antigox[canal] = novox[canal];
                        antigoy[canal] = novoy[canal];
                    }
                }
                pictureBoxSD[pictureBoxSelecionado].Refresh();
            }
        }

        public void setGanho(double ganhoSD)
        {
            this.ganhoSD = ganhoSD;
            if (ganhoSD == 0.5)
                deslocamentoSD = (int)(819); //0,5V = 819     1,0V = 1639
            else if (ganhoSD == 1)
                deslocamentoSD = 0;
            else if (ganhoSD == 2)
                deslocamentoSD = -(int)(819 / 2);
            rePlota();
        }

        public void setVelocidade(int escalaTempoPictureBox)
        {
            this.escalaTempoPictureBox = escalaTempoPictureBox;

            if (inputStream != null)
            {
                inputStream.Position = 0;
                atualizaTelaDadosSD();
            }
        }

        //Move leitura do arquivo para o início do arquivo
        public void reset()
        {
            int tempoReferencia;
            form.btnFazerMedidas.Enabled = false;
            posicaoArquivo = 0;
            tempoReferencia = posicaoArquivo / (12 * 60);
            tempoTotalSegundos = posicaoArquivo / (12);

            //Atualiza tempo total do arquivo lido
            form.msktxtbxAtual.Text = String.Format("{0:D2}{1:D2}{2:D2}", tempoReferencia / 60, tempoReferencia % 60, tempoTotalSegundos % 60);

            if (inputStream != null)
            {
                inputStream.Position = posicaoArquivo * 512;
                atualizaTelaDadosSD();
            }
        }

        //Avança posição de leitura do arquivo de acordo com o selecionado
        public void avanca()
        {
            int tempoReferencia;
            int numSegundosQuadro;
            form.btnFazerMedidas.Enabled = false;

            switch (avancaRecua)
            {
                case 0: //Avança 1 min
                    posicaoArquivo = posicaoArquivo + 60 * 12; //cada 12 setor 1s
                    if (posicaoArquivo >= numeroTotalSetores)
                        posicaoArquivo = posicaoArquivo - 60 * 12;
                    break;
                case 1: //Avança 10 min
                    posicaoArquivo = posicaoArquivo + 60 * 12 * 10;
                    if (posicaoArquivo >= numeroTotalSetores)
                        posicaoArquivo = posicaoArquivo - 60 * 12 * 10;
                    break;
                case 2: //Avança 1 hora
                    posicaoArquivo = posicaoArquivo + 60 * 12 * 60;
                    if (posicaoArquivo >= numeroTotalSetores)
                        posicaoArquivo = posicaoArquivo - 60 * 12 * 60;
                    break;
                case 3: //Avança 1 quadro
                    numSegundosQuadro = 4 * (escalaTempoPictureBox / 960);
                    posicaoArquivo = posicaoArquivo + numSegundosQuadro * 12;
                    if (posicaoArquivo >= numeroTotalSetores)
                        posicaoArquivo = posicaoArquivo - numSegundosQuadro * 12;
                    break;
            }

            tempoReferencia = posicaoArquivo / (12 * 60);
            tempoTotalSegundos = posicaoArquivo / (12);

            //Atualiza tempo total do arquivo lido
            form.msktxtbxAtual.Text = String.Format("{0:D2}{1:D2}{2:D2}", tempoReferencia / 60, tempoReferencia % 60, tempoTotalSegundos % 60);

            if (inputStream != null)
            {
                inputStream.Position = posicaoArquivo * 512;
                atualizaTelaDadosSD();
            }
        }

        //Recua posição de leitura do arquivo de acordo com o selecionado
        public void recuar()
        {
            int tempoReferencia;
            int numSegundosQuadro;
            form.btnFazerMedidas.Enabled = false;

            switch (avancaRecua)
            {
                case 0: //Recua 1 min
                    posicaoArquivo = posicaoArquivo - 60 * 12;
                    if (posicaoArquivo < 0)
                        posicaoArquivo = 0;
                    break;
                case 1: //Recua 10 min
                    posicaoArquivo = posicaoArquivo - 60 * 12 * 10;
                    if (posicaoArquivo < 0)
                        posicaoArquivo = 0;
                    break;
                case 2: //Recua 1 hora
                    posicaoArquivo = posicaoArquivo - 60 * 12 * 60;
                    if (posicaoArquivo < 0)
                        posicaoArquivo = 0;
                    break;
                case 3: //Recua 1 quadro
                    numSegundosQuadro = 4 * (escalaTempoPictureBox / 960);
                    posicaoArquivo = posicaoArquivo - numSegundosQuadro * 12;
                    if (posicaoArquivo < 0)
                        posicaoArquivo = 0;
                    break;            

            }

            tempoReferencia = posicaoArquivo / (12 * 60);
            tempoTotalSegundos = posicaoArquivo / (12);

            //Atualiza tempo total do arquivo lido
            form.msktxtbxAtual.Text = String.Format("{0:D2}{1:D2}{2:D2}", tempoReferencia / 60, tempoReferencia % 60, tempoTotalSegundos % 60);

            if (inputStream != null)
            {
                inputStream.Position = posicaoArquivo * 512;
                atualizaTelaDadosSD();
            }
        }

        //Seleciona Impressão de Aceleração
        public void ativarAceleracao()
        {
            form.btnFazerMedidas.Enabled = false;

            if (mostrarAceleracao)
            {
                mostrarAceleracao = false;
                form.btnDemostrarAceleracao.Text = "Demo Acelerometros (4x3)";
                if (inputStream != null)
                {
                    inputStream.Position = 0;
                    atualizaTelaDadosSD();
                }
            }
            else
            {
                mostrarAceleracao = true;
                form.btnDemostrarAceleracao.Text = "Sair da Demonstração";
                if (inputStream != null)
                {
                    inputStream.Position = 0;
                    atualizaTelaDadosSD();
                }
            }
        }

        public void pictureBoxSDClick(MouseEventArgs mouseEvent, int pctboxSelectedSD)
        {
            int inicioDetalhe;
            Graphics objGrafico;
            this.pctboxSelectedSD = pctboxSelectedSD;

            this.rePlota();

            Pen p = new Pen(Color.Red, 0);
            p.Width = 2;
            objGrafico = Graphics.FromImage(pictureBoxSD[pctboxSelectedSD].Image);
            objGrafico.DrawEllipse(p, mouseEvent.X - 5, mouseEvent.Y - 5, 10, 10);

            //Localiza o ponto falido mais próximo
            derivacaoSelecionada = (int)(mouseEvent.Y / (pictureBoxSD[pctboxSelectedSD].Height / 3));
            posicaoSelecionada = (int)(mouseEvent.X * escalaTempoPictureBox / pictureBoxSD[pctboxSelectedSD].Width + pctboxSelectedSD * escalaTempoPictureBox);
            inicioDetalhe = 0;
            if ((posicaoSelecionada - tamanhoDetalhe / 2) > 0)
            {
                inicioDetalhe = (posicaoSelecionada - tamanhoDetalhe / 2);
            }


            for (int i = inicioDetalhe; i < inicioDetalhe + tamanhoDetalhe; i++)
            {
                if (mostrarAceleracao)
                {
                    amostrasDetalhada[i - inicioDetalhe] = amostrasAceleracao[derivacaoSelecionada, i];
                }
                else
                {
                    amostrasDetalhada[i - inicioDetalhe] = amostrasSD[derivacaoSelecionada, i];
                }
            }

            pictureBoxSD[pctboxSelectedSD].Refresh();
            form.btnFazerMedidas.Enabled = true;
        }

        public int getNumeroDeBlocos()
        {
            return numeroTotalSetores;
        }
		
		public void realizaAnaliseMitDTW()
		{
			LeitorMit.realizaAnaliseDTW(4000);
		}
		
		public void realizaAnaliseMitHiperCubo()
		{
			LeitorMit.realizaAnaliseHipercubo();
		}
		
		public void realizaAnaliseDadosDTW()
		{
			
			int[] arrayInicial = getDadosIniciais();
			analisador = new AnalisadorDTW(arrayInicial);
			while(inputStream.Position<inputStream.Length){
               	separaDados();
				analisador.analisarTrecho(ArrayUtil.getOneDimensionArray(amostrasSD,1));
				amostrasSD = null;
			}
		}
		
		public void realizaAnaliseDadosHiperCubo()
		{
			
			int[] arrayInicial = getDadosIniciais();
			analisador = new AnalisadorHiperCubo();
			
			while(inputStream.Position<inputStream.Length){
               	separaDados();
				analisador.analisarTrecho(ArrayUtil.getOneDimensionArray(amostrasSD,1));
				amostrasSD = null;
			}
			
		}
		
		public int[] getDadosIniciais()
		{
			inputStream.Position = 0;
			separaDados();
			/*int[] primeiraMetade = ;
			separaDados();
			int[] segundaMetade = ArrayUtil.getOneDimensionArray(amostrasSD,1);
			
			int[] meuArray = new int[primeiraMetade.Length+segundaMetade.Length];
			
			primeiraMetade.CopyTo(meuArray,0);
			segundaMetade.CopyTo(meuArray,primeiraMetade.Length);*/
			
			return ArrayUtil.getOneDimensionArray(amostrasSD,1);
		}


    }
}
